package lookup;

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 层次性依赖查找
 * 类似双亲委派机制
 * @author jackcfan
 * @date 2021/9/13
 */
public class HierarchicalLookupTest {

    private static BeanFactory createParentBeanFactory(){
        return new ClassPathXmlApplicationContext("dependency-lookup-context.xml");
    }

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.register(HierarchicalLookupTest.class);
        applicationContext.refresh();

        // 1 获取 HierarchicalBeanFactory
        // ConfigurableListableBeanFactory
        //      -> ConfigurableBeanFactory
        //          -> HierarchicalBeanFactory
        ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();

        // 2 设置 parentBeanFactory
        beanFactory.setParentBeanFactory(createParentBeanFactory());

        // containsLocalBean()
        System.out.println("本容器不包含 user bean :"+ !beanFactory.containsLocalBean("user"));

        // containsBean
        System.out.println("父容器包含 user bean :"+ beanFactory.getParentBeanFactory().containsBean("user"));

        // 使用递归检查双亲容器是否包含 Bean
        System.out.println("容器包含 user bean :"+ containsBean(beanFactory,"user"));

        applicationContext.close();
    }

    /**
     * 参考：
     * {@link org.springframework.beans.factory.BeanFactoryUtils#beanOfTypeIncludingAncestors} <p>
     * 类似 ClassLoader 双亲委派，先去父容器中找，找不到再在当前容器找
     * */
    private static boolean containsBean(BeanFactory beanFactory, String beanName){
        if(beanFactory instanceof HierarchicalBeanFactory){
            HierarchicalBeanFactory hierarchicalBeanFactory = (HierarchicalBeanFactory)beanFactory;
            BeanFactory parentBeanFactory = hierarchicalBeanFactory.getParentBeanFactory();
            if(parentBeanFactory == null){
                return hierarchicalBeanFactory.containsLocalBean(beanName);
            }
            if(containsBean(parentBeanFactory, beanName)){
                return true;
            }
        }
        return beanFactory.containsBean(beanName);
    }
}
